﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using VectorMath;

namespace DOEgbXML
{
    public class DOEgbXMLBasics
    {
        public class EdgeFamily
        {
            public List<Vector.MemorySafe_CartCoord> startendpt;
            public string sbdec;
            public List<EdgeFamily> relatedEdges;
        }

        public static bool SliversAllowed = true;

        public enum MeasurementUnits
        {
            cubicft,
            sqft,
            ft,
            spaces,
            levels,
        }

        public class Tolerances
        {
            public const double ToleranceDefault = -999;
            public const double VolumeTolerance = 1.0;
            public const double AreaTolerance = 1.0;
            public const double SpaceAreaPercentageTolerance = 0.025;

            public const double coordToleranceIP = 0.05;
            public const double coordToleranceM = 0.015;

            //Level (aka - story) height difference tolerance in feet
            public const double LevelHeightTolerance = 0.1;
            public const double VectorAngleTolerance = 2.5;
            public const double SpaceAreaTolerance = 1;
            //all count tolerances
            public const double SpaceCountTolerance = 0;
            public const double LevelCountTolerance = 0;
            public const double SurfaceCountTolerance = 0;
            public const double ExteriorWallCountTolerance = 0;
            public const double InteriorWallCountTolerance = 0;
            public const double InteriorFloorCountTolerance = 0;
            public const double RoofCountTolerance = 0;
            public const double AirWallCountTolerance = 0;
            public const double OpeningCountTolerance = 0;
            public const double FixedWindowCountTolerance = 0;
            public const double OperableWindowCountTolerance = 0;
            public const double FixedSkylightCountTolerance = 0;
            public const double OperableSkylightCountTolerance = 0;
            public const double SlidingDoorCountTolerance = 0;
            public const double NonSlidingDoorCountTolerance = 0;
            public const double AirOpeningCountTolerance = 0;

            //surface tolerances
            public const double SurfaceHeightTolerance = 0.5; //feet
            public const double SurfaceWidthTolerance = 0.5; //feet
            public const double SurfaceTiltTolerance = 2.5; // degrees
            public const double SurfaceAzimuthTolerance = 2.5; //degrees
            public const double SurfaceInsPtXTolerance = 0.5; //feet
            public const double SurfaceInsPtYTolerance = 0.5; //feet
            public const double SurfaceInsPtZTolerance = 0.5; //feet
            public const double SurfacePLCoordTolerance = 0.5; //feet (3 inches)
            public const double SliverDimensionTolerance = 0.25; //feet
            public const double SurfaceAreaPercentageTolerance = 0.025;

            //opening tolerances
            public const double OpeningHeightTolerance = 0.5; //feet
            public const double OpeningWidthTolerance = 0.5; //feet
            public const double OpeningSurfaceInsPtXTolerance = 0.5; //feet
            public const double OpeningSurfaceInsPtYTolerance = 0.5; //feet
            public const double OpeningSurfaceInsPtZTolerance = 0.5; //feet
            public const double OpeningAreaPercentageTolerance = 0.025;
        }

        static public double FindTilt(Vector.MemorySafe_CartVect normalVector)
        {
            double calculatedTilt = -999;
            //may need to also take into account other factors that, at this stage, seem to not be important
            //building Direction of Relative North
            //zone Direction of Relative North
            //GlobalGeometryRules coordinate system
            //I may need to know this in the future then rotate the axis vectors I am making below

            //x-axis [1 0 0] points east, y-axis [0 1 0] points north, z-axis[0 0 1] points up to the sky
            //alignment with y axis means north pointing, alignment with z-axis means it is pointing up to the sky (like a flat roof)
            double nX = 0;
            double nY = 1;
            double nZ = 0;
            Vector.MemorySafe_CartVect northVector = new Vector.MemorySafe_CartVect(nX, nY, nZ);

            double uX = 0;
            double uY = 0;
            double uZ = 1;
            Vector.MemorySafe_CartVect upVector = new Vector.MemorySafe_CartVect(uX, uY, uZ);

            //rotate the axis vectors for the future

            //ensure the vector passed into the function is a unit vector
            normalVector = Vector.UnitVector(normalVector);
            //get tilt:  cross product of normal vector and upVector
            //since parallel and anti parallel vectors will return the same cross product [0,0,0] I need to filter out the antiparalll case
            if (normalVector.X == upVector.X * -1 && normalVector.Y == upVector.Y * -1 && normalVector.Z == upVector.Z * -1)
            {
                calculatedTilt = 180;
                return calculatedTilt;
            }
            else
            {
                Vector.MemorySafe_CartVect tiltVector = Vector.CrossProduct(normalVector, upVector);
                double tiltVectorMagnitude = Vector.VectorMagnitude(tiltVector);
                calculatedTilt = Math.Round(Math.Asin(tiltVectorMagnitude) * 180 / Math.PI, 2);
                return calculatedTilt;
            }
        }


        static public double FindAzimuth(Vector.MemorySafe_CartVect normalVector)
        {
            double calculatedAzimuth = -999;
            //may need to also take into account other factors that, at this stage, seem to not be important
            //building Direction of Relative North
            //zone Direction of Relative North
            //GlobalGeometryRules coordinate system
            //I may need to know this in the future then rotate the axis vectors I am making below

            //x-axis [1 0 0] points east, y-axis [0 1 0] points north, z-axis[0 0 1] points up to the sky
            //alignment with y axis means north pointing, alignment with z-axis means it is pointing up to the sky (like a flat roof)

            Vector.MemorySafe_CartVect northVector = new Vector.MemorySafe_CartVect(0, 1, 0);

            Vector.MemorySafe_CartVect southVector = new Vector.MemorySafe_CartVect(0, -1, 0);

            Vector.MemorySafe_CartVect eastVector = new Vector.MemorySafe_CartVect(1, 0, 0);

            Vector.MemorySafe_CartVect westVector = new Vector.MemorySafe_CartVect(-1, 0, 0);

            Vector.MemorySafe_CartVect upVector = new Vector.MemorySafe_CartVect(0, 0, 1);

            //rotate the axis vectors for the future

            //ensure the vector passed into the function is a unit vector
            normalVector = Vector.UnitVector(normalVector);
            //get X-Y projection of the normal vector
            //normalVector.Z = 0;
            //get azimuth:  cross product of normal vector x-y projection and northVector
            //1st quadrant
            if ((normalVector.X == 0 && normalVector.Y == 1) || (normalVector.X == 1 && normalVector.Y == 0) || (normalVector.X > 0 && normalVector.Y > 0))
            {
                //get azimuth:  cross product of normal vector x-y projection and northVector
                Vector.MemorySafe_CartVect azVector = Vector.CrossProduct(normalVector, northVector);
                double azVectorMagnitude = Vector.VectorMagnitude(azVector);

                //modification for when the vector is in different quadrants
                calculatedAzimuth = Math.Round(Math.Asin(azVectorMagnitude) * 180 / Math.PI, 2);
                return calculatedAzimuth;
            }
            //second quadrant
            else if (normalVector.X < 0 && normalVector.Y > 0)
            {
                Vector.MemorySafe_CartVect azVector = Vector.CrossProduct(normalVector, westVector);
                double azVectorMagnitude = Vector.VectorMagnitude(azVector);

                //modification for when the vector is in different quadrants
                calculatedAzimuth = Math.Round(Math.Asin(azVectorMagnitude) * 180 / Math.PI, 2) + 270;
                return calculatedAzimuth;
            }
            //quadrant 3
            else if ((normalVector.X < 0 && normalVector.Y < 0) || (normalVector.X == -1 && normalVector.Y == 0))
            {
                Vector.MemorySafe_CartVect azVector = Vector.CrossProduct(normalVector, southVector);
                double azVectorMagnitude = Vector.VectorMagnitude(azVector);

                //modification for when the vector is in different quadrants
                calculatedAzimuth = Math.Round(Math.Asin(azVectorMagnitude) * 180 / Math.PI, 2) + 180;
                return calculatedAzimuth;
            }
            //quadrant 4
            else if ((normalVector.X > 0 && normalVector.Y < 0) || (normalVector.X == 0 && normalVector.Y == -1))
            {
                Vector.MemorySafe_CartVect azVector = Vector.CrossProduct(normalVector, eastVector);
                double azVectorMagnitude = Vector.VectorMagnitude(azVector);

                //modification for when the vector is in different quadrants
                calculatedAzimuth = Math.Round(Math.Asin(azVectorMagnitude) * 180 / Math.PI, 2) + 90;
                return calculatedAzimuth;
            }
            //this will happen to vectors that point straight down or straight up because we are only interested in the X-Y projection and set the Z to zero anyways
            else if (normalVector.X == 0 && normalVector.Y == 0)
            {
                calculatedAzimuth = 0;
                return calculatedAzimuth;
            }

            //get the 

            return calculatedAzimuth;
        }

    }
}